#include <iostream>

#include "edaBestImprSelect.h"
#include "edaHC.h"
#include "edaSA.h"
#include "edaSeqWrapperControl.h"
#include "edaExpCoolingSchedule.h"
#include "edaGenContinue.h"
#include "edaTS.h"
#include "edaSimpleMoveTabuList.h"
#include "edaImprBestFitAspirCrit.h"
#include "graph.h"
#include "mySolution.h"
#include "myTwoOpt.h"
#include "myTwoOptNext.h"
#include "myTwoOptMoveRandom.h"

int main(int argc, char **argv)
{
  if (argc != 2) {
    std::cerr << "Usage : ./mySFWSearch [instance]" << std::endl;
    return 1;
  }

  srand(time(NULL));

  Graph graph;

  graph.load(argv[1]);

  mySolution route(graph);;

  std::cout << "[From] " << route << std::endl;

  myTwoOpt two_opt(graph);
  myTwoOptNext two_opt_next(graph);
  edaBestImprSelect moveSelect;
  edaHC hcSearch( &two_opt, &two_opt_next, &moveSelect);

  myTwoOpt two_opt1(graph), two_opt2(graph);
  myTwoOptMoveRandom two_opt_random1(graph), two_opt_random2(graph);
  edaExpCoolingSchedule coolingSchedule1(0.01, 0.98), coolingSchedule2(0.01, 0.90);
  edaGenContinue cont_criteria1(1000), cont_criteria2(1000);
  edaSA saSearch1( &two_opt1, &two_opt_random1, &cont_criteria1, 
		   1100.0, &coolingSchedule1);
  edaSA saSearch2( &two_opt2, &two_opt_random2, &cont_criteria2, 
		   1900.0, &coolingSchedule2);

  myTwoOpt two_opt3(graph);
  myTwoOptNext two_opt_next3(graph);
  edaSimpleMoveTabuList tabuList;
  edaImprBestFitAspirCrit aspirCrit;
  edaGenContinue cont_criteria3(1000);
  edaTS tsSearch(&two_opt3, 
		 &two_opt_next3, 
		 &tabuList, 
		 &aspirCrit, 
		 &cont_criteria3);

  edaSeqWrapperControl sfControl;
  int hcid1 = sfControl.insertVertex( &hcSearch );
  int hcid2 = sfControl.insertVertex( &hcSearch );
  int said1 = sfControl.insertVertex( &saSearch1 );
  int said2 = sfControl.insertVertex( &saSearch2 );
  int tsid1 = sfControl.insertVertex( &tsSearch );
  sfControl.insertEdge( hcid1, said1 ); 
  sfControl.insertEdge( hcid1, said2 );
  sfControl.insertEdge( said1, hcid2 );
  sfControl.insertEdge( said2, hcid2 );
  sfControl.insertEdge( tsid1, said1 );

  sfControl.search(route);

  std::cout << "[To] " << route << std::endl;
  std::cout << "[To Fitness] " << route.fullEvaluate() << std::endl;

  return 0;
}

edaSerialize *userClassGenerate(int clsid)
{
  switch( clsid ){
  case _USERCLASSID_ + _CLSID_TWO_OPT_:
    return new myTwoOpt;

  case _USERCLASSID_ + _CLSID_TWO_OPT_NEXT_:
    return new myTwoOptNext;

  case _USERCLASSID_ + _CLSID_MY_SOLUTION_:
    return new mySolution;

  case _USERCLASSID_ + _CLSID_TWO_OPT_MOVE_RANDOM_:
    return new myTwoOptMoveRandom;
    
  case _USERCLASSID_ + _CLSID_GRAPH_:
    return new Graph;
    
  default:
    std::cerr << "Unknown classId " << clsid << " for object generation!!!" << std::endl;
    exit(-1);
  }
}

